package com.lion.common.modules.uaa.service.impl;

import com.lion.common.base.exceptions.CommonException;
import com.lion.common.modules.uaa.dao.repository.UaaAccountRepository;
import com.lion.common.modules.uaa.dao.repository.UaaAccountRoleRepository;
import com.lion.common.modules.uaa.domain.entity.UaaAccountEntity;
import com.lion.common.modules.uaa.domain.entity.UaaAccountRoleEntity;
import com.lion.common.modules.uaa.service.assistants.AccountInitAssistantImpl;
import com.lion.common.modules.uaa.service.assistants.RegisterAssistantImpl;
import com.lion.common.modules.uaa.service.assistants.VerifyCodeAssistantImpl;
import com.lion.common.modules.uaa.service.def.AccountService;
import com.lion.common.modules.uaa.web.models.params.CompleteAccountParam;
import com.lion.common.modules.uaa.web.models.results.UserInfoResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * @author Chris Chan
 * Create On 2025/7/25 下午8:41
 * Use for:
 * Explain:
 */
@Slf4j
@Service
public class AccountServiceImpl implements AccountService<UaaAccountEntity> {
    private static final String VCODE_ERROR = "验证码错误";
    private static final String USERNAME_MISSED = "账号不存在";

    private UaaAccountRepository uaaAccountRepository;
    private UaaAccountRoleRepository uaaAccountRoleRepository;
    private AccountInitAssistantImpl accountInitAssistant;
    private VerifyCodeAssistantImpl verifyCodeAssistant;
    private PasswordEncoder passwordEncoder;
    private RegisterAssistantImpl registerAssistant;

    @Autowired
    public AccountServiceImpl(UaaAccountRepository uaaAccountRepository, UaaAccountRoleRepository uaaAccountRoleRepository, AccountInitAssistantImpl accountInitAssistant, VerifyCodeAssistantImpl verifyCodeAssistant, PasswordEncoder passwordEncoder, RegisterAssistantImpl registerAssistant) {
        this.uaaAccountRepository = uaaAccountRepository;
        this.uaaAccountRoleRepository = uaaAccountRoleRepository;
        this.accountInitAssistant = accountInitAssistant;
        this.verifyCodeAssistant = verifyCodeAssistant;
        this.passwordEncoder = passwordEncoder;
        this.registerAssistant = registerAssistant;
    }

    @Transactional
    @Override
    public void addAccountWithUsernamePassword(String username, String password) {
        // 校验用户名
        if (!StringUtils.hasText(username)) {
            throw CommonException.of("用户名不能为空");
        }
        // 校验密码
        if (!StringUtils.hasText(password)) {
            throw CommonException.of("密码不能为空");
        }
        // 密码安全性校验
        if (!registerAssistant.isPasswordSecurity(password)) {
            throw CommonException.of("密码安全性不足");
        }
        // 校验用户名是否存在
        UaaAccountEntity account = uaaAccountRepository.findByUsername(username);
        if (account != null) {
            throw CommonException.of("用户名已存在");
        }
        // 密码加密
        String encodePassword = passwordEncoder.encode(password);
        // 创建用户账号
        UaaAccountEntity uaaAccountEntity = new UaaAccountEntity();
        uaaAccountEntity.setUsername(username);
        uaaAccountEntity.setPassword(encodePassword);
        uaaAccountEntity.setEmail(null);
        uaaAccountEntity.setMobile(null);
        uaaAccountRepository.save(uaaAccountEntity);
        // 创建用户角色关联
        createAccountRole(uaaAccountEntity.getCode(), 2L);//默认角色: USER
        // 向用户手机发送激活码
    }

    @Transactional
    @Override
    public void addAccountWithMobileVerifyCode(String mobile) {
        //创建用户账号
        UaaAccountEntity uaaAccountEntity = new UaaAccountEntity();
        uaaAccountEntity.setUsername(null);
        uaaAccountEntity.setPassword(accountInitAssistant.generateInitPassword());//初始密码
        uaaAccountEntity.setEmail(null);
        uaaAccountEntity.setMobile(mobile);
        uaaAccountRepository.save(uaaAccountEntity);

        // 创建用户角色关联
        this.createAccountRole(uaaAccountEntity.getCode(), 2L);//默认角色: USER
        // 向用户手机发送激活码

    }

    @Transactional
    @Override
    public void addAccountWithEmailVerifyCode(String email) {
        //创建用户账号
        UaaAccountEntity uaaAccountEntity = new UaaAccountEntity();
        uaaAccountEntity.setUsername(null);
        uaaAccountEntity.setPassword(accountInitAssistant.generateInitPassword());//初始密码
        uaaAccountEntity.setEmail(email);
        uaaAccountEntity.setMobile(null);
        uaaAccountRepository.save(uaaAccountEntity);

        // 创建用户角色关联
        createAccountRole(uaaAccountEntity.getCode(), 2L);//默认角色: USER
        // 向用户邮箱发送激活码
    }

    @Override
    public UaaAccountEntity findAccountByUsername(String username) {
        return uaaAccountRepository.findByUsername(username);
    }

    @Override
    public UaaAccountEntity findAccountByMobile(String mobile) {
        return uaaAccountRepository.findByMobile(mobile);
    }

    @Override
    public UaaAccountEntity findAccountByEmail(String email) {
        return uaaAccountRepository.findByEmail(email);
    }

    @Transactional
    @Override
    public void resetPassword(UaaAccountEntity account) {
        account.setPassword(accountInitAssistant.generateInitPassword());
        uaaAccountRepository.save(account);
        // 向用户邮箱发送重置密码通知
    }

    @Transactional
    @Override
    public boolean activateAccount(String activationCode) {
        UaaAccountEntity account = uaaAccountRepository.findByActivationCode(activationCode);
        if (account == null) {
            throw CommonException.of("激活码错误");
        }
        account.setActivationCode(null);
        uaaAccountRepository.save(account);
        // 发送激活成功通知
        return true;
    }

    @Transactional
    @Override
    public boolean completeAccount(CompleteAccountParam param) {
        // 从JWT中获取账号编码
        Long accountCode = getCurrentAccountCode();
        // 分离参数
        String username = param.getUsername();
        String cellphone = param.getCellphone();
        String email = param.getEmail();
        String verifyCode = param.getVerifyCode();
        String password = param.getPassword();
        // 校验图片验证码
        boolean verify = verifyCodeAssistant.checkGraphVerifyCode(verifyCode);
        if (!verify) {

            throw CommonException.of(VCODE_ERROR);
        }
        // 取出账号数据
        UaaAccountEntity account = uaaAccountRepository.findByCode(accountCode);
        if (account == null) {
            throw CommonException.of(USERNAME_MISSED);
        }
        // username、cellphone、email 不能重复
        UaaAccountEntity accountByUsername = uaaAccountRepository.findByUsername(username);
        if (accountByUsername != null && !accountByUsername.getCode().equals(accountCode)) {
            throw CommonException.of("用户名已存在");
        }
        UaaAccountEntity accountByCellphone = uaaAccountRepository.findByMobile(cellphone);
        if (accountByCellphone != null && !accountByCellphone.getCode().equals(accountCode)) {
            throw CommonException.of("手机号已存在");
        }
        UaaAccountEntity accountByEmail = uaaAccountRepository.findByEmail(email);
        if (accountByEmail != null && !accountByEmail.getCode().equals(accountCode)) {
            throw CommonException.of("邮箱已存在");
        }
        // 完善账号数据
        if (account.getUsername() == null && StringUtils.hasText(username)) {
            account.setUsername(username);
        }
        if (account.getMobile() == null && StringUtils.hasText(cellphone)) {
            account.setMobile(cellphone);
        }
        if (account.getEmail() == null && StringUtils.hasText(email)) {
            account.setEmail(email);
        }
        account.setPassword(passwordEncoder.encode(password));
        uaaAccountRepository.save(account);
        return true;
    }

    @Transactional
    @Override
    public boolean updatePasswordByMobileVerifyCode(String mobile, String verifyCode, String newPassword, String confirmPassword) {
        // 校验手机号验证码
        boolean verify = verifyCodeAssistant.checkSmsVerifyCode(mobile, verifyCode);
        if (!verify) {
            throw CommonException.of(VCODE_ERROR);
        }
        // 取出账号数据
        UaaAccountEntity account = uaaAccountRepository.findByMobile(mobile);
        if (account == null) {
            throw CommonException.of(USERNAME_MISSED);
        }
        // 更新密码
        account.setPassword(passwordEncoder.encode(newPassword));
        uaaAccountRepository.save(account);
        return true;
    }

    @Transactional
    @Override
    public boolean updatePasswordByEmailVerifyCode(String email, String verifyCode, String newPassword, String confirmPassword) {
        // 校验邮箱验证码
        boolean verify = verifyCodeAssistant.checkEmailVerifyCode(email, verifyCode);
        if (!verify) {
            throw CommonException.of(VCODE_ERROR);
        }
        // 取出账号数据
        UaaAccountEntity account = uaaAccountRepository.findByEmail(email);
        if (account == null) {
            throw CommonException.of(USERNAME_MISSED);
        }
        // 更新密码
        account.setPassword(passwordEncoder.encode(newPassword));
        uaaAccountRepository.save(account);
        return true;
    }

    @Override
    public boolean logout() {
        // 清除缓存的token，同时前端自行清除token
        return true;
    }

    @Override
    public void createAccountRole(Long accountCode, Long roleCode) {
        UaaAccountRoleEntity uaaAccountRoleEntity = new UaaAccountRoleEntity();
        uaaAccountRoleEntity.setAccountCode(accountCode);
        uaaAccountRoleEntity.setRoleCode(roleCode);
        uaaAccountRoleRepository.save(uaaAccountRoleEntity);
    }

    @Transactional
    @Override
    public boolean updateAccountRole(Long accountCode, List<Long> roleCodes) {
        // 先删除旧的角色
        uaaAccountRoleRepository.deleteByAccountCode(accountCode);
        // 再添加新的角色
        for (Long roleCode : roleCodes) {
            createAccountRole(accountCode, roleCode);
        }
        return true;
    }

    @Override
    public Long getCurrentAccountCode() {
        return Optional.ofNullable(SecurityContextHolder.getContext())
                .map(SecurityContext::getAuthentication)
                .map(Authentication::getPrincipal)
                .filter(principal -> principal instanceof Jwt)
                .map(jwt -> ((Jwt) jwt).getClaim("userCode"))
                .map(String::valueOf)
                .map(Long::valueOf)
                .orElse(null);
    }

    @Override
    public List<String> getCurrentAccountAuthorities() {
        return Optional.ofNullable(SecurityContextHolder.getContext())
                .map(SecurityContext::getAuthentication)
                .map(Authentication::getPrincipal)
                .filter(principal -> principal instanceof Jwt)
                .map(jwt -> ((Jwt) jwt).getClaim("authorities"))
                // 转换为List
                .map(authorities -> (List<String>) authorities)
                .orElse(Collections.emptyList());
    }

    @Override
    public UserInfoResult getUserInfo() {
        // 从JWT中获取账号编码
        Long accountCode = getCurrentAccountCode();
        // 取出账号数据
        UaaAccountEntity account = uaaAccountRepository.findByCode(accountCode);
        if (account == null) {
            throw CommonException.of(USERNAME_MISSED);
        }
        // 转换为UserInfoResult
        return new UserInfoResult(account.getCode(), account.getUsername(), account.getMobile(), account.getEmail(), "http://localhost:8080/a.png", getCurrentAccountAuthorities());
    }
}
